home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 1.iso / desktop / papcw10.zip / WINCMD.DOC < prev    next >
Text File  |  1994-07-01  |  49KB  |  1,044 lines

  1. WINCMD.EXE (VERSION 1.4)                Copyright (c) 1993 Douglas Boling
  2. -------------------------------------------------------------------------
  3.                  First Published in PC Magazine April 27,1993 (Utilities)
  4. -------------------------------------------------------------------------
  5.  
  6. WINCMD:
  7.                 WINCMD is a Windows-based command file interpreter that
  8. lets you create simple Windows 3.1 specific programs to automate repetivive
  9. tasks.
  10.  
  11.      Remember the DOS batch files with which you once proudly automated
  12. all your routine tasks?  If you've joined the mad rush to Windows, you've
  13. simply had to learn to do without this useful and convenient facility.
  14. The DOS batch file language may have been limited, but Windows supported
  15. nothing at all in its place--until now.
  16.  
  17.    WINCMD.EXE, this issue's utility, is a Windows-based command file
  18. interpreter that lets you create simple Windows programs that perform
  19. the repetitive functions that were once the domain of DOS batch files.
  20. WINCMD goes far beyond the simple DOS batch file language, however.
  21. Its language includes looping and branching statements  along with
  22. user-defined subroutines and functions.  Both numeric and string
  23. variables are supported, as is a full suite of arithmetic and logical
  24. operators.
  25.  
  26.      You can use any ASCII editor, such as Notepad, to create WINCMD
  27. programs.  Typically, these programs will carry a .WCM extension, though
  28. this is not required unless you want the program to be callable from
  29. another WINCMD program.  A single .WCM file can be up to 64K in size,
  30. though its executable parts (those not made up of comment lines) are
  31. limited to about 45K.
  32.  
  33.  USING WINCMD
  34.  
  35.       Before discussing how to use WINCMD, I must start with some
  36. terminology.  WINCMD.EXE is the Windows program I've written.
  37. It interprets programs--which are ASCII files--that are written in the
  38. WINCMD language.  To keep the two kinds of programs separate, I'll use
  39. the full name and extension, WINCMD.EXE, when referring to the utility
  40. itself.  I'll refer to the ASCII files that WINCMD.EXE interprets as
  41. WINCMD programs.
  42.  
  43.      To install WINCMD.EXE, just copy it, along with WINCMD.ICO (its
  44. icon file) and any .WCM files you have (two are supplied with the
  45. program), into a directory on your path.  Select the FileNew menu item
  46. in the Program Manager and choose Program Item.  Enter the short title
  47. you want to appear under the icon as the Description, and enter the
  48. complete path and WINCMD.EXE on the command line.
  49.  
  50.      To make it easy to run WINCMD programs, you should then also use
  51. the File Manager to associate the .WCM file extension with WINCMD.EXE.
  52. To do this, start the Windows File Manager and select the FileAssociate
  53. menu item.  When the dialog box appears enter WCM, the WINCMD default
  54. extension, in the edit box.  In the Combo Box that lists the programs,
  55. enter the path to and filename of WINCMD.EXE.  Click on the OK button
  56. and you're set!
  57.  
  58.      From now on, any time you click on a WINCMD file in the File Manager
  59. or Program Manager, Windows will automatically start WINCMD.EXE and pass
  60. it the name of your WINCMD program.  When WINCMD.EXE is started with a
  61. filename on the command line, it will immediately start executing that
  62. file.  When WINCMD.EXE has finished executing the WINCMD program, it
  63. will gracefully terminate.
  64.  
  65.      Since debugging is important even for WINCMD programs, WINCMD.EXE
  66. provides help in this area.  If WINCMD.EXE is started with an /L command
  67. switch before the WINCMD program name, WINCMD.EXE will display a window
  68. with your WINCMD program loaded into memory, ready to execute.  Be sure
  69. not to place the /L after the WINCMD program name, or it will be
  70. considered an argument to the command file.  When WINCMD.EXE starts,
  71. it performs some preprocessing on your WINCMD program.  If it finds any
  72. lines it does not understand, you'll get appropriate print error messages
  73. with line numbers to help you find the problem.
  74.  
  75.      Error messages are displayed for such faults as lines being too long
  76. or numbers too big.  When an error message is printed, WINCMD.EXE changes
  77. to display two windows. The listing window displays the WINCMD program
  78. with the line highlighted that is to be executed next.  The output window
  79. displays the last 100 lines printed by the WINCMD program as well as the
  80. error messages.
  81.  
  82.      WINCMD.EXE allows you to run a WINCMD program from the window in two
  83. different ways.  The program can be run normally either by pressing the
  84. Run button or by selecting the RunRun Program menu selection.  The
  85. WINCMD.EXE window will then change to display only the output window and
  86. run the WINCMD program.  The Run button text will change to Stop.
  87.  
  88.       Pressing the Stop button will cause WINCMD.EXE to stop executing
  89. the WINCMD program and to display both the output and listing windows.
  90. Again, the line in the program that would have been executed next is
  91. highlighted.  The program can then be restarted from this point simply
  92. by clicking on the Run button.  If you want to start the program from
  93. the beginning, first click on the Reset button to reset the program and
  94. then hit the Run button to start the program on its way.  Note that when
  95. WINCMD resets a program, it rereads the program from the disk.  This
  96. means that you can make changes to the program and then you can have
  97. WINCMD load those changes by pressing the Reset button.
  98.  
  99.      The other way to run a WINCMD program is by stepping through it
  100. one line at a time.  Single stepping is very handy to see exactly how
  101. a WINCMD program is being executed.  Each press of the Step button will
  102. cause WINCMD.EXE to execute one line of the WINCMD program.  The listing
  103. window will highlight the next line to be executed.
  104.  
  105. WINCMD VARIABLES AND ARITHMETIC
  106.  
  107.      The WINCMD syntax combines the power of a high-level language with
  108. the simple command line operation of a batch language.  Before discussing
  109. the different WINCMD statements in detail, I should explain how WINCMD
  110. programs use variables.  The WINCMD language makes no distinction between
  111. string variables and numeric variables.  That is, a variable that has
  112. been assigned a string value can later be assigned a number and vice versa.
  113. Variables do not have to be declared before they are used.  As you would
  114. expect, variables are assigned using the equal sign.
  115.  
  116.      The following three  statements are examples of valid WINCMD
  117. assignments.
  118.  
  119.                      var = 1
  120.                      var = magazine
  121.                      var = "I like PC Magazine"
  122.  
  123.      In the first assignment above, the variable VAR is given the
  124. value 1.  The second assignment has the variable assigned the string
  125. ``magazine.''  In the third assignment, VAR is assigned the string ``I
  126. like PC Magazine.''  The quotes allow spaces to be included in the string
  127. assigned to VAR.  If the quotes were not used, WINCMD would attempt to
  128. assign the variable VAR with the string ``I'', but would then find the
  129. additional characters on the line.  WINCMD would then stop execution and
  130. print the error message ``Extra characters on line.''
  131.  
  132.      Variable names may contain numbers, letters, or the characters
  133. _, $, %, and #, but the first character in a variable must always be
  134. either a letter or underscore (_).  Variable names are not case-sensitive;
  135. the names BOB, Bob, and bob all refer to the same variable.  Variable names
  136. can be up to 253 characters long.  Variables can be used anywhere strings
  137. or numbers can be used in the program.
  138.  
  139.      The numbers you use may range from -2,147,483,648 to 2,147,483,647,
  140. and can be expressed in binary, octal, decimal, or hexadecimal format.
  141. (In entering numbers, do not type in the commas shown above, however.)
  142. The WINCMD default is base 10.  To enter a nondecimal number, start the
  143. number with a zero, then use b, o, or x as the second character,
  144. indicating a binary, octal, or hexadecimal number, respectively.  The
  145. following four lines demonstrate different ways to write the decimal
  146. value 100.
  147.  
  148.                       var = 100
  149.                       var = 0x64
  150.                       var = 0o144
  151.                       var = 0b1100100
  152.  
  153.      WINCMD uses the standard set of arithmetic operators for addition
  154. (+), subtraction (-), multiplication (*), and division (/).
  155. Arithmetic comparisons can be performed for greater than (>), less than
  156. (<), greater than or equal to (>=), less than or equal to (<=), and not
  157. equal (<>) operators.  Comparison operators return a nonzero value if
  158. the condition is true and a zero if the condition is false.
  159.  
  160.      As in BASIC, the equal sign (=) performs double duty in WINCMD.
  161. When placed alone on a line to the right of a variable, it indicates
  162. an assignment, as in var = 5.  In any other location, however, it
  163. indicates a test for equality.  WINCMD also supports double equals (==)
  164. as an equality operator.  The equality test works for both numbers and
  165. strings.  For example, to test if the variable MONTH is ``February'',
  166. simply use the expression
  167.  
  168.                            month = "February"
  169.  
  170.      WINCMD also includes a set of logical and bitwise operators.  The
  171. logical operators AND, OR, XOR, and NOT act on the logical value.  If a
  172. variable is 0, its logical value is FALSE; otherwise, its logical value
  173. is TRUE.  For example, the numbers 5 and -3 are TRUE values while 0 is a
  174. FALSE value.  The logical operators allow you to combine other tests into
  175. one condition.  For example, the expression
  176.  
  177.                           DAY = "Monday" AND MONTH <> "February"
  178.  
  179. will evaluate to TRUE only if both DAY is equal to Monday and MONTH is
  180. not ``February''.
  181.  
  182.      The bitwise operators ANDB, ORB, XORB, and NOTB perform logical
  183. operations on each bit in a number.  For example, 5 ANDB 20 returns a
  184. value of 4.
  185.  
  186.               (00101 ANDB 10100 = 00100).
  187.  
  188.  
  189.       When placed between two strings, the plus sign (+) indicates that
  190. the strings should be concatenated.  For example,
  191.  
  192.                    CITYSTATE = "Knoxville " + "Tennessee"
  193.  
  194. will assign the variable CITYSTATE to the string ``Knoxville Tennessee''.
  195.  
  196. WINCMD STATEMENTS
  197.  
  198.      A list of the statements and functions in the WINCMD language is
  199. shown in Figure 1 (below).  To cause WINCMD to launch a program or to
  200. execute a DOS command, simply include that program or command on a
  201. separate line.  For example, to start the Windows Notepad editor, simply
  202. type the name of the program on a line, as in
  203.  
  204.                                                NOTEPAD
  205.  
  206. If no extension for the program to be launched is specified, WINCMD will
  207. look for each of the extensions listed in the Programs key in the
  208. [Windows] section of WIN.INI until the particular program is found.
  209. If no path is specified, WINCMD follows the same search procedure Windows
  210. uses when starting a program from the Program Manager.  What this means
  211. is that WINCMD first looks in the current directory, followed by the
  212. Windows and Windows System directories, then the WINCMD directory, the
  213. directories listed in the PATH statement, and finally any directories
  214. that are mapped on a network.
  215.  
  216.      Executing DOS internal commands is as easy as launching programs.
  217. To copy the file WINCMD.C to WINCMD.BAK, just include the command on the
  218. line as you would if you were typing it in from the DOS command line:
  219.  
  220.                       COPY WINCMD.C WINCMD.BAK
  221.  
  222. When WINCMD sees a DOS internal command, such as COPY or DEL, it
  223. launches the command processor listed in the COMSPEC statement in the
  224. WINCMD environment.
  225.  
  226.      If Windows is running in Enhanced mode and your _DEFAULT.PIF file
  227. is configured to run DOS programs in a window, DOS internal commands
  228. will be executed in the background.  Since the WINCMD language uses
  229. some of the same special characters--such as the asterisk (*)--as
  230. the DOS command line does, you will need to enclose any filenames in
  231. quotation marks.  For example, to copy all files with a .C extension
  232. to .BAK, just enclose the filenames in quotation marks as follows.
  233.  
  234.                         COPY "*.C D:\BACKUP"
  235.  
  236.      One major difference between the action of a WINCMD file and a DOS
  237. batch file is that WINCMD programs continue to execute after a program
  238. has been launched.  In DOS, if a batch file starts a program, it waits
  239. until that program terminates before continuing.  In the example that
  240. follows, how-ever, a WINCMD program launches three programs: Notepad,
  241. Word for Windows, and WordPerfect for DOS.
  242.  
  243.                                            NOTEPAD
  244.                                            WINWORD
  245.                                            WP
  246.  
  247.      Since WINCMD programs do not wait for a program to finish before
  248. continuing to the next line, all three programs will start at
  249. approximately the same time. WINCMD programs continue until there are no
  250. more lines in a program or an EXIT statement is encountered.
  251.  
  252.      The EXIT statement is used to stop execution of a WINCMD program.
  253. In the following example, therefore, Notepad and WordPerfect for DOS will
  254. be executed, but Word for Windows will not, since its line comes after
  255. the EXIT statement.
  256.  
  257.                       NOTEPAD
  258.                       WP
  259.                       EXIT
  260.                       WINWORD
  261.  
  262.      Comments can be included in WINCMD files by using the REM statement.
  263. WINCMD ignores any characters from the REM statement to the end of the
  264. line.  To provide a syntax similar to that of BASIC and C, comments can
  265. also be indicated by the single quote (') or by double forward slashes
  266. (//):
  267.  
  268.        rem This is a comment line in WINCMD
  269.        // This is too.
  270.        '  Don't forget me!
  271.  
  272.  
  273.      While I will later discuss a more elegant way for WINCMD programs
  274. to talk to the user, the simplest way is to use the SAY and PRINT
  275. statements.  (SAY and PRINT perform the same function.)  While the
  276. SAY/PRINT function is similar in the function of the SAY statement in
  277. REXX, I have included the PRINT alias for all those users familiar with
  278. BASIC.
  279.  
  280.    The SAY statement displays a line that appears in the output window
  281. of the WINCMD.EXE window.  If WINCMD.EXE is minimized when a SAY
  282. statement is encountered, the window will be restored so that the user
  283. can read the text of the message.  The SAY statement first evaluates
  284. whatever is on the line beyond the SAY statement, and then it displays
  285. the results in the output window.  The following two statements will
  286. provide an example of SAY and PRINT:
  287.  
  288. SAY I think that five times 3 is 5 * 3 "and that six divided by two is " 6/2
  289.  
  290. PRINT I think that five times 3 is 5 * 3 "and that six divided by two is " 6/2
  291.  
  292.  
  293. When either of the above two lines is executed, the line:
  294.  
  295.  
  296. I THINK THAT FIVE TIMES 3 IS 15 and that six divided by two is 3
  297.  
  298. will appear.  Notice that the words outside of the quotation marks
  299. are capitalized, but that the string enclosed in quotation marks is
  300. lowercase.  Unlike BASIC's PRINT statement, the different expressions
  301. do not have to be separated by commas or semicolons.
  302.  
  303.      Branching is performed with the IF statement.  The IF statement will
  304. execute the next line if the condition included in the IF statement is
  305. true (or non-zero).  While not required, the THEN statement can be used
  306. either on the same line as the IF or on the next line.  If the optional
  307. ELSE keyword is used and the expression evaluates to zero, the first
  308. statement beyond the ELSE keyword is executed.  The syntax for the IF
  309. statement is as follows:
  310.  
  311.                         IF expression
  312.                         [THEN]
  313.                            {statement}
  314.                         [ELSE
  315.                            {statement}]
  316.  
  317.      The square and curly brackets in the diagram above are not part of
  318. the syntax--you don't enter them in a WINCMD program.  The IF, THEN, and
  319. ELSE statements are capitalized and the statements are indented only for
  320. readability.  The expression is to be replaced with any variable or
  321. equation, and statement represents any valid WINCMD line.
  322.  
  323.      As a concrete example of the IF statement at work, consider the
  324. following:
  325.  
  326.                IF BOB > 5
  327.                THEN
  328.                   BOB = BOB + 2
  329.  
  330. Here, if the variable BOB is greater than 5, BOB will be set to its
  331. current value plus 2.  If you added an ELSE statement, the example
  332. might become
  333.  
  334.                  IF BOB > 5
  335.                  THEN
  336.                     BOB = BOB + 2
  337.                  ELSE
  338.                     BOB = BOB + 1
  339.  
  340. In this case, if the variable BOB is greater than 5, BOB will be
  341. increased by 2; otherwise BOB will be increased by 1. Since the THEN
  342. statement is optional, this could equivalently have been written as
  343.  
  344.                       IF BOB > 5
  345.                          BOB = BOB + 2
  346.                       ELSE
  347.                          BOB = BOB + 1
  348.  
  349.       Note that the IF statement will only execute one statement line
  350. for a THEN or ELSE clause.  To get around this, you can use the DO and
  351. END statements, which permit grouping multiple statements as if written
  352. on a single line.  DO...END blocks of statements can be included in both
  353. the THEN and ELSE clauses of the IF statement.  The DO and END statement
  354. syntax is as follows:
  355.  
  356.                        DO
  357.                           {statement}
  358.                           {statement}
  359.                               .
  360.                               .
  361.                               .
  362.                           {statement}
  363. END
  364.  
  365.  
  366.      As an example of using DO and END to include more than the one
  367. statement within the IF-THEN-ELSE structure, consider
  368.  
  369.                         IF BOB > 5 AND DAY = "Monday"
  370.                            DO
  371.                               BOB = BOB + 2
  372.                               FRED = BOB - 2
  373.                               JOE = BOB + FRED
  374.                            END
  375.                            ELSE
  376.                               DO
  377.  
  378.                                 COPY WINCMD.C WINCMD.BAK
  379.                                 JOE = BOB/2 + 2
  380.                               END
  381.  
  382. Here, DO END statements enclose the three statements of the THEN clause
  383. and the two statements of the ELSE clause.  Note also that a more
  384. complex condition is used.  In this example, the THEN clause will be
  385. executed only if BOB is greater than 5 and DAY equals the string
  386. ``Monday.''
  387.  
  388.      Loops are performed by the WHILE statement, whose syntax is
  389.  
  390.                           WHILE {condition}
  391.                              {statement}
  392.  
  393. The WHILE statement evaluates the condition and, if the condition is
  394. non-zero (that is, if it is TRUE), the line indicated by statement is
  395. executed.  The WHILE statement then re-tests the condition and, if the
  396. result is still non-zero, it executes the statement again.  WHILE will
  397. thus continue to test the condition and execute the statement until
  398. the condition evaluates to zero.  Like the IF statement, the WHILE
  399. statement works only on the statement line that immediately follows the
  400. WHILE, but this statement line can be the start of a DO...END block.
  401. Thus, multiple statements can be executed in the loop.
  402.  
  403.      The example below sets the variable COUNT to 10, and then enters a
  404. WHILE loop that decrements COUNT each time through until COUNT equals
  405. zero.
  406.  
  407.            COUNT = 10
  408.            WHILE COUNT > 0
  409.            DO
  410.                 COUNT = COUNT - 1
  411.                 FRED = FRED * FRED
  412.            END
  413.  
  414.      If you want to leave a WHILE loop before its condition evaluates
  415. to false, you can use the LEAVE statement.  When WINCMD.EXE sees a LEAVE
  416. statement, the loop is immediately exited, even if there are other
  417. statements after it.  The next statement to execute will be the first
  418. one beyond the loop.  In the next example, the loop terminates if the
  419. variable ERROR becomes non-zero.
  420.  
  421.  
  422.                WHILE FRED <> BOB
  423.                DO
  424.                  BOB = BOB + 1
  425.  
  426.  
  427.                  REM
  428.                  REM INSERT OTHER LINES HERE
  429.                  REM
  430.  
  431.  
  432.                  IF ERROR
  433.                       LEAVE
  434.  
  435.  
  436.                  REM
  437.                  REM ANY STATEMENTS AFTER THE
  438.                  REM LEAVE WILL NOT BE EXECUTED IF
  439.                  REM ERROR NOT 0
  440.                  REM
  441.  
  442. END
  443.  
  444.  
  445. SUBROUTINES AND FUNCTIONS
  446.  
  447.      The WINCMD language allows you to create subroutines and functions.
  448. Actually, WINCMD makes no distinction between functions and subroutines.
  449. If a user-defined routine is called while evaluating an expression, the
  450. routine is treated as a function and the value returned by the routine
  451. replaces the function name. If the user-defined routine is called on a
  452. separate line, it is treated as a subroutine and any value returned by
  453. the routine is simply ignored.
  454.  
  455.      The start of a subroutine is defined by a label, which is quite
  456. simply the name of the subroutine.  A label must be a valid variable
  457. name; that is, it must start with a letter or underscore and it must
  458. be less than 253 characters in length.  The last character of a label
  459. must be a colon (:).  A subroutine is terminated by a RETURN statement.
  460. There is no limit to the number of statements that can be used in a
  461. subroutine.
  462.  
  463.      In the following example, the subroutine WASTETIME is called to
  464. waste a little time in the program.
  465.  
  466.                        BOB = BOB + 1
  467.                        WASTETIME
  468.                        BOB = BOB + 4
  469.                        EXIT
  470.  
  471.                        WASTETIME:
  472.                           COUNT = 1000
  473.                           WHILE COUNT > 0
  474.                              COUNT = COUNT - 1
  475. RETURN
  476.  
  477.  
  478. In this example the variable BOB is incremented, after which the
  479. subroutine is called.  The loop is executed in the subroutine and
  480. the subroutine returns, upon which BOB is increased by 4. The EXIT
  481. statement then prevents the program from continuing down through the
  482. WASTETIME subroutine again. You must always EXIT a subroutine.
  483.  
  484.      You can pass parameters to subroutines by enclosing the parameters
  485. in parentheses after the variable name.  Multiple parameters are separated
  486. by commas.  Below, I've modified the former example to pass the number
  487. 1000 and the variable BOB to the WASTETIME routine.
  488.  
  489.                           BOB = BOB + 1
  490.                           WASTETIME (1000, BOB)
  491.                           BOB = BOB + 4
  492.                           EXIT
  493.  
  494.                           WASTETIME:
  495.                              COUNT = ARG(1)
  496.                              WHILE COUNT > ARG (2)
  497.                                 COUNT = COUNT - 1
  498.                           RETURN
  499.  
  500.      Subroutines retrieve their arguments by using the built-in ARG()
  501. function.  ARG() returns the subroutine parameter indicated by the number
  502. passed to it; that is, ARG(1) returns the first parameter, ARG(2) the
  503. second, and so on.  If a subroutine attempts to read a parameter that was
  504. not passed, ARG() returns a null string. If ARG() is called with no
  505. arguments, it returns the number of parameters passed to the subroutine.
  506. ARG (0) returns the name of the routine that was called.
  507.  
  508.      If the ARG() function is called outside a subroutine or function,
  509. it returns the command line arguments to the program.  Just as the %1
  510. and %2 return the first and second arguments in a DOS batch file, ARG(1)
  511. and ARG(2) will return those parameters for a WINCMD file.  ARG(0) returns
  512. the name of the WINCMD program, and ARG() returns the number of parameters
  513. on the command line.
  514.  
  515.      In the example below, the user-defined function MAX returns the
  516. value of the largest argument passed to it:
  517.  
  518.                       BOB = MAX (300, FRED, SAM, JOE) * 3
  519.                       EXIT
  520.  
  521.                       MAX:
  522.                       COUNT = ARG()
  523.                       MAXVAL = ARG(1)
  524.                       WHILE COUNT > 0
  525.                       DO
  526.                           IF  MAXVAL < ARG(COUNT)
  527.                               MAXVAL = ARG (COUNT)
  528. END
  529. RETURN MAXVAL
  530.  
  531.  
  532. In the code above, MAX uses ARG() to determine how many arguments have
  533. been passed to it.  It then compares each argument and returns the value
  534. of MAXVAL on the RETURN line.  When MAX has finished, the variable BOB
  535. will be assigned the highest value of all the arguments passed, multiplied
  536. by 3.
  537.  
  538.      WINCMD variables are global:  If a variable is modified in a
  539. subroutine, the change will also be reflected in the variable when the
  540. subroutine is finished.  WINCMD does not support any form of local
  541. variables, nor does it currently let you get rid of a variable that has
  542. been defined.
  543.  
  544. WINCMDBUILT-INFUNCTIONS
  545.  
  546.      WIN-CMD has a number of built-in functions that make it easier to
  547. create useful programs.  These functions can be divided into two types:
  548. general programming functions and functions designed to control Windows
  549. applications.  The LENGTH() function returns the number of characters
  550. in a string.  For example, in the line
  551.  
  552.  
  553.                            BOB = LENGTH ("Holston Hills")
  554.  
  555.      BOB would be assigned 13.
  556.      The SUBSTR() function, which is similar to the like-named functions
  557. in BASIC and REXX, returns a portion of a string. SUBSTR() is called with
  558. three parameters, which determine the portion of the string returned.
  559. The first argument is the original string; the second argument is the
  560. starting character; and the last argument is the number of characters to
  561. return.  In the following example, the variable FRED is assigned the
  562. string ``bcdef'', which represents the second through the seventh
  563. characters of the string ``abcdefghi.''
  564.  
  565.                         FRED = SUBSTR ("abcdefghi", 2, 5)
  566.  
  567.      The UCASE() function returns an uppercase version of the string
  568. passed as its parameter.  The string passed is not changed.  In the
  569. next example, BOB is assigned ``BCDEF'' while FRED remains ``bcdef''.
  570.  
  571.                               FRED = "BCDEF"
  572.                               BOB = UCASE (FRED)
  573.  
  574.      The DELAY() function holds up the execution of the next line in the
  575. program for a specified number of milliseconds.  While the delay time
  576. can range from 1 to 65,355 ms, in practice numbers less than 100 are
  577. not useful. Using the DELAY() function is preferrable to simple looping
  578. as a way of killing time, because during a DELAY() function WINCMD.EXE
  579. is idle and does not take any processor time away from other applications.
  580.  
  581.      The MSGBOX() function lets a WINCMD program display a standard Windows
  582. Message Box.  The function takes three parameters:  the text of the message
  583. box; the title of the message box; and a configuration parameter that tells
  584. Windows which buttons and icon to display in the box.  The usable
  585. configuration parameters are shown in Figure 2 (below).  The various
  586. values listed can be combined by using the ORB operator.  The MSGBOX()
  587. function also returns a value that depends on which button you press.
  588. Figure 2 also shows what these returned values mean.
  589.  
  590.      The following example displays a very disturbing message box.
  591.  
  592.  
  593. REPLY = MsgBox ("Your disk is trashed", "Disk Error", 2 ORB 0x30 ORB 0x1000)
  594.  
  595.  
  596. This message box displays ``Your disk is trashed'' in a message box
  597. titled ``Disk Error,'' together with an Exclamation icon.  The box will
  598. have three buttons, Abort, Retry, and Ignore, and will be system-modal.
  599. The value in the variable REPLY depends on which button the user presses.
  600.  
  601.      The ASKBOX() function displays a dialog box with a message and an
  602. entry field.  This function allows WINCMD programs to ask the user for
  603. input.  The two parameters to the function are the question to ask the
  604. user and the default answer for the entry field.  ASKBOX will display
  605. a dialog box with OK and Cancel buttons.  If the user presses OK, the
  606. function returns the text in the entry field.  If the user presses the
  607. Cancel button, the function returns a null string.
  608.  
  609.      The GETAPPACTIVE() function returns the text of the active window
  610. on the Windows desktop.  (This is the window on the desktop that has the
  611. active colored title bar.)  The text returned is the text from the title
  612. bar of this window.  For example, if Notepad has just been started and
  613. has the input focus, the text returned by GETAPPACTIVE() will be
  614. ``Notepad - (Untitled).''  The GETAPPACTIVE() function has no input
  615. paramters.
  616.  
  617.      The APPACTIVATE() function activates the window whose title bar
  618. text matches that supplied as the single parameter to the function.
  619. For example, to set the input focus to the Program Manager, the function
  620. would look like this:
  621.  
  622.                       APPACTIVATE("Program Manager")
  623.  
  624. The function returns the text of the previously active window if the
  625. function was successful, otherwise it returns 0.
  626.  
  627.      In using APPACTIVATE you must bear in mind that many programs add
  628. things to their window titles.  Notepad, for example, adds the current
  629. filename; Program Manager adds the name of a program group that's
  630. maximized, and so on.  Unfortunately, APPACTIVATE can't recognize these
  631. expanded titles.
  632.  
  633.      The SENDKEYS() function provides a way for WINCMD programs to control
  634. Windows applications by sending keystrokes to the application that has
  635. the current input focus.  SENDKEYS takes only one string argument, but
  636. that string can simulate every key on the keyboard, including the Ctrl,
  637. Alt, and Shift keys.
  638.  
  639.      The format of the SENDKEYS() input string is similar to the strings
  640. used by the SENDKEYS functions in WordBASIC and Visual BASIC.  Unlike
  641. WordBASIC and Visual BASIC, however, in a WINCMD program you set the
  642. active application before sending the keys, not after.  Most keys can
  643. be sent to an application simply by including the letter in the input
  644. string.  For example, to send the three keys a, b, and c to the Program
  645. Manager, just use the following two lines in your WINCMD program:
  646.  
  647.                      APPACTIVATE("Program Manager")
  648.                      SENDKEYS ("abc")
  649.  
  650.      To send a shifted key, simply precede the letter with ^,  %, or +
  651. character to simulate the Ctrl, Alt, or Shift key, respectively.  The
  652. shifting prefixes can be combined, so you can create combinations such
  653. as Ctrl-Shift-Alt-W.
  654.  
  655.      If you want to hold the shifting key down for a number of keys,
  656. enclose the keys in parentheses.  For example, to send the f and x keys
  657. while holding down the Alt key, use the command
  658.  
  659.                               SENDKEYS ("%(fx)")
  660.  
  661.      Special keys, such as Enter, Escape, and Tab, can be sent using an
  662. alias for the key, enclosed in brackets .  A list of the recognized key
  663. aliases is shown in Figure 3 (below).  For example, to send Enter and Tab
  664. keys to an application, use the command
  665.  
  666.                               SENDKEYS(entertab)
  667.  
  668.      To send the such keys as +, ^, and %, enclose the key in brackets
  669. thus:
  670.  
  671.                               SENDKEYS("+")
  672.  
  673.      Note that I have enclosed most of the SENDKEY strings in quotes.
  674. This is because many of the characters in a SENDKEY string may be
  675. characters that WINCMD would otherwise interpet for its own use.
  676. The plus key and the parenthesis keys are examples.  To avoid having
  677. WINCMD do something you do not want, simply enclose the string in
  678. quotes.  Since there is no harm in using the quotes, I recommend you
  679. use them consistently.
  680.  
  681.      One additional caution is that SENDKEYS() works by placing simulated
  682. keystrokes in Windows' system event queue.  Since this queue can become
  683. filled if you send too many characters at once, it's a good idea to break
  684. up the keys that you send into blocks of fewer than five keys.  Since
  685. WINCMD.EXE yields to other applications between each line of a WINCMD
  686. program, sending keys on consecutive lines will not present a problem.
  687.  
  688.      The GETAPPEXE() function returns the name of the program that
  689. created the window with the matching title text.  GETAPPEXE() is handy
  690. for determining whether a particular program is running.  For example,
  691.  
  692.                        GETAPPEXE("Program Manager")
  693.  
  694. will return PROGMAN.EXE.  Note again, however, that the match to the
  695. window title text must be exact.
  696.  
  697.      The final WINCMD function, TICKS() returns the number of milliseconds
  698. since Windows was started.  TICKS() takes no arguments.
  699.  
  700. WINCMD EXAMPLES
  701.  
  702.      The power of WINCMD is best demonstrated by example.  SEARCH.WCM,
  703. the first of the two sample programs I've included with this utility,
  704. uses the File Manager to search a disk for matching files.  The WINCMD
  705. program is listed in Figure 4 (below).  The second program, 2CLIP.WCM,
  706. uses Notepad to copy a file into the Windows Clipboard.  Both programs
  707. use features of the standard Accessories bundled with Windows to help
  708. perform the function of the WINCMD program.  The programs also
  709. demonstrate the power of the SENDKEYS function in controlling other
  710. programs.
  711.  
  712.      WINCMD.EXE allows you to write command files with which you can
  713. control your favorite Windows applications.  However, WINCMD.EXE is
  714. not the last that you will hear about the WINCMD language.  In the
  715. next installment of this column, I will present a DLL that hooks into
  716. WINCMD.EXE to provide dozens of helpful functions for your WINCMD
  717. programs, so be sure to stay tuned!
  718. ------------------------------------------------------------------------
  719. DOUGLAS BOLING IS A CONTRIBUTING EDITOR TO PC MAGAZINE.
  720. ------------------------------------------------------------------------
  721.  
  722. =============================================================================
  723.                    WINCMD Statements and Functions
  724.  
  725.  
  726. STATEMENT               DESCRIPTION
  727. -----------------------------------------------------------------------------
  728. IF{expression}          Branching statement
  729. [THEN]
  730.    {statement}
  731. [ELSE]
  732.    {statement}
  733. -----------------------------------------------------------------------------
  734. DO                      Block statement
  735.    {statement}
  736.    {statement}
  737.         .
  738.         .
  739.         .
  740.    {statement}END
  741. -----------------------------------------------------------------------------
  742. WHILE {condition}       Loop statement
  743.   {statement}
  744. -----------------------------------------------------------------------------
  745. EXIT [return code]      Terminates a WINCMD program
  746. -----------------------------------------------------------------------------
  747. RETURN [return code]    Terminates a subroutine
  748. -----------------------------------------------------------------------------
  749. LEAVE                   Exits from a loop
  750. -----------------------------------------------------------------------------
  751. PRINT {expression}      Displays a line of text to the user
  752. -----------------------------------------------------------------------------
  753. SAY   {expression}      Displays a line of text to the user
  754. -----------------------------------------------------------------------------
  755. REM {text}              Comment, remainder of text on the line ignored
  756. -----------------------------------------------------------------------------
  757. // {text}               Comment, remainder of text on the line ignored
  758. -----------------------------------------------------------------------------
  759. '  {text}               Comment, remainder of text on the line ignored
  760. -----------------------------------------------------------------------------
  761.  
  762. FUNCTION                      DESCRIPTION
  763. -----------------------------------------------------------------------------
  764. LENGTH(string)                Returns the length of a string.
  765. -----------------------------------------------------------------------------
  766. UCASE(string)                 Returns a copy of the string in upper case
  767.                                characters.
  768. -----------------------------------------------------------------------------
  769. SUBSTR(string,start,length)   Returns a part of a string.
  770. -----------------------------------------------------------------------------
  771. ARG(number)                   Returns an argument to program or a subroutine.
  772. -----------------------------------------------------------------------------
  773. DELAY(number)                 Halts program execution for a number of
  774.                                milliseconds.
  775. -----------------------------------------------------------------------------
  776. APPACTIVATE(win title text)   Activates the window with the matching title
  777.                                text.
  778. -----------------------------------------------------------------------------
  779. GETAPPACTIVE (no parameters)  Returns the title text of the currently active
  780.                                 window.
  781. -----------------------------------------------------------------------------
  782. GETAPPEXE(win title text)     Returns the EXE file name for a window.
  783. -----------------------------------------------------------------------------
  784. GETNEXTAPP(win title text)    Returns the window text of the next window on
  785.                                 the screen
  786. -----------------------------------------------------------------------------
  787. SENDKEYS(send key string)     Sends a series of keys to the active application
  788. ------------------------------------------------------------------------------
  789. MSGBOX(message,title,flags)   Displays a message box
  790. ------------------------------------------------------------------------------
  791. ASKBOX(text, default answer)  Displays a dialog box so that the user can enter
  792.                                a value.
  793. ------------------------------------------------------------------------------
  794. TICKS(no parameters)          Returns the number of miliseconds since Windows
  795.                                was started.
  796. ------------------------------------------------------------------------------
  797. LibVer (WinCmd Library Name)  Returns the version number of a WinCmd library.
  798.                                 0 if Lib not found
  799. ------------------------------------------------------------------------------
  800. GetEnvVar (Env Variable Name) Returns the value of an environment variable.
  801.                                 The name is case sensitive
  802. ------------------------------------------------------------------------------
  803.  
  804. Figure 1:  These statements and functions are supported in the WINCMD
  805.                 language.
  806. ==============================================================================
  807.  
  808.                       WINCMD BSGBOX FUNCTIONS
  809.  
  810.  
  811. VALUE                   PRODUCES
  812. -----------------------------------------------------------------------------
  813. 0x0000                  OK Button
  814. 0x0001                  OK and Cancel Buttons
  815. 0x0002                  Abort, retry and Ignore Buttons
  816. 0x0003                  Yes, No, Cancel Buttons
  817. 0x0004                  Yes and No Buttons
  818. 0x0005                  Retry and Cancel Buttons
  819. 0x0010                  Hand Icon
  820. 0x0020                  Question mark Icon
  821. 0x0030                  Exclamation Icon
  822. 0x0040                  Asterisk Icon
  823. 0x0000                  Sets default button to button 1
  824. 0x0100                  Sets default button to button 2
  825. 0x0200                  Sets default button to button 3
  826. 0x1000                  Creates System modal message box
  827. 0x2000                  Creates Application modal message box
  828.  
  829. RETURN VALUE            MEANING
  830. -----------------------------------------------------------------------------
  831. 1                       OK button pressed
  832. 2                       Cancel button pressed
  833. 3                       Abort button pressed
  834. 4                       Retry button pressed
  835. 5                       Ignore button pressed
  836. 6                       Yes button pressed
  837. 7                       No button pressed
  838.  
  839. Figure 2:  These are the values that can be passed to the MsgBox function
  840. and the meaning of the values returned.
  841. =============================================================================
  842.  
  843.          WinCmd Key Aliases
  844.  
  845.  
  846. KEY                      ALIAS
  847. -----------------------------------------------------------------------------
  848. BACKSPACE                {bksp}
  849. -----------------------------------------------------------------------------
  850. BREAK                    {break}
  851. -----------------------------------------------------------------------------
  852. CAPSLOCK                 {capslock}
  853. -----------------------------------------------------------------------------
  854. CLEAR                    {clear}
  855. -----------------------------------------------------------------------------
  856. DEL                      {delete}
  857. -----------------------------------------------------------------------------
  858. DOWN ARROW               {down}
  859. -----------------------------------------------------------------------------
  860. END                      {end}
  861. -----------------------------------------------------------------------------
  862. ENTER                    {enter}
  863. -----------------------------------------------------------------------------
  864. ESC                      {esc}
  865. -----------------------------------------------------------------------------
  866. HELP                     {help}
  867. -----------------------------------------------------------------------------
  868. HOME                     {home}
  869. -----------------------------------------------------------------------------
  870. INS                      {insert}
  871. -----------------------------------------------------------------------------
  872. LEFT ARROW               {left}
  873. -----------------------------------------------------------------------------
  874. NUM LOCK                 {numlock}
  875. -----------------------------------------------------------------------------
  876. PAGE DOWN                {pgdn}
  877. -----------------------------------------------------------------------------
  878. PAGE UP                  {pgup}
  879. -----------------------------------------------------------------------------
  880. PRINT SCREEN             {prtsc}
  881. -----------------------------------------------------------------------------
  882. RIGHT ARROW              {right}
  883. -----------------------------------------------------------------------------
  884. TAB                      {tab}
  885. -----------------------------------------------------------------------------
  886. UP ARROW                 {up}
  887. -----------------------------------------------------------------------------
  888. F1                       {F1}
  889. -----------------------------------------------------------------------------
  890. F2                       {F2}
  891. -----------------------------------------------------------------------------
  892. F3                       {F3}
  893. -----------------------------------------------------------------------------
  894. F4                       {F4}
  895. -----------------------------------------------------------------------------
  896. F5                       {F5}
  897. -----------------------------------------------------------------------------
  898. F6                       {F6}
  899. -----------------------------------------------------------------------------
  900. F7                       {F7}
  901. -----------------------------------------------------------------------------
  902. F8                       {F8}
  903. -----------------------------------------------------------------------------
  904. F9                       {F9}
  905. -----------------------------------------------------------------------------
  906. F10                      {F10}
  907. -----------------------------------------------------------------------------
  908. F11                      {F11}
  909. -----------------------------------------------------------------------------
  910. F12                      {F12}
  911. -----------------------------------------------------------------------------
  912. To shift a key precede the key with one of the following three characters.
  913.  
  914. SHIFT                    +(plus sign)
  915. -----------------------------------------------------------------------------
  916. ALT                      %(percent sign)
  917. -----------------------------------------------------------------------------
  918. CTRL                     ^(caret)
  919. -----------------------------------------------------------------------------
  920.  
  921. Figure 3: The aliases above are used by the SENDKEYS() function to send
  922.           "special key" keystrokes to applications.
  923. ==============================================================================
  924.  
  925.  
  926. //---------------------------------------------------------
  927. // WinCmd program that uses file manager to
  928. // search a disk for a set of files.
  929. //---------------------------------------------------------
  930. //
  931. // Ask user for file spec.  Default to all files
  932. //
  933. ans = AskBox ("Enter the file name to look for", "*.*")
  934. //
  935. // If user pressed the Cancel button, quit
  936. //
  937. if ans+a == a
  938.    exit
  939. //
  940. // If the file manager isn't running, start it
  941. //
  942. if (AppActivate ("File Manager") = 0)
  943.    winfile
  944. //
  945. // Send keys to File Manager to search disk.
  946. //
  947. sendkeys ("%-n")         //Minimize directory tree window
  948. sendkeys ("%fh")         //Open file search dialog
  949. sendkeys (ans)           //Enter file spec 
  950. sendkeys ("{tab}")       //Tab to directory window
  951. sendkeys ("c:\")         //Enter hard drive root
  952. sendkeys ("{enter}")     //Start search
  953. sendkeys ("%-x")         //Maximize search results window
  954. exit
  955.  
  956. ------------------------------------------------------------------------
  957. Figure 4:  SEARCH.WCM is a WinCmd program that uses the File Mangaer to
  958.            search for files on a disk.
  959. =============================================================================
  960.  
  961.  
  962. //-----------------------------------------------------
  963. // 2CLIP.WCM--WinCmd program that copies a text file into
  964. // the Windows Clipboard.
  965. //-----------------------------------------------------
  966. //
  967. // Ask user for file name.  Default to blank
  968. //
  969. ans = AskBox ("Enter the name of the file to copy into the clipboard"," ")
  970. //
  971. // If user pressed the Cancel button, quit
  972. //
  973. if ans+a == a
  974.    exit
  975. //
  976. // Start NotePad
  977. //
  978. notepad
  979.  
  980. //
  981. // Send keys to notepad to read in the file
  982. //
  983. sendkeys ("%fo")         //Display the file open dialog box
  984. sendkeys (ans)           //Enter file spec
  985. sendkeys ("{enter}")     //Open the file.
  986. //
  987. // See if notepad read the file.  If it didn't, the warning box
  988. // for the "Open" dialog will be active, and GetAppActive() will
  989. // return "Open".  In that case, close notepad and tell the user
  990. //
  991. winact = Getappactive()
  992. if (winact = "Open") do
  993.    sendkeys ("{enter}")  //Close the warning box
  994.    sendkeys ("{esc}")    //Close the file open box
  995.    ok = fail
  996. end
  997. else do
  998.    sendkeys ("%ea")      //Select all the text
  999.    sendkeys ("%ec")      //Copy the data into the clipboard
  1000.    ok = pass
  1001. end
  1002. sendkeys ("%fx")         //Close notepad
  1003. if (ok = fail)
  1004.    msgbox ("Notepad could not access the file you requested.  Nothing was copied into the clipboard", "Error!", 0)
  1005.  
  1006. exit
  1007.  
  1008. --------------------------------------------------------------------------
  1009. Figure 5: 2CLIP.WCM uses the NOTEPAD to copy a file onto the Windows
  1010.           Clipboard.
  1011. ==========================================================================
  1012.  
  1013. Revision History:
  1014.  
  1015.                   1.0   Inital Release
  1016.  
  1017.                   1.1   Fixed AppendString bug
  1018.                         Fixed Lib load directory find
  1019.                         Fixed Cmp Op assignment bug
  1020.                         Fixed Launch bug
  1021.                         Removed trailing space from ResolveLine code
  1022.                         Allowed \ and : in variable names
  1023.                         Added WINCMDVER predefined var
  1024.                         Added Library About menus
  1025.                         Added Help screen
  1026.  
  1027.                   1.2   Fixed end of file problem causing GPFs
  1028.                         Added hooks to allow statements in libraries
  1029.                         Added hooks for library provided error messages
  1030.                         Added hooks for ON type statements
  1031.  
  1032.                   1.3   Fixed SendKey F10 problem.
  1033.                         Fixed problem with signed compare functions
  1034.                         Cleaned up termination code
  1035.                         Fixed library statement hooks
  1036.                         Fixed Stop statement asych problem
  1037.                         Fixed incomplete reset problem
  1038.                         Added LaunchSpecial statement
  1039.                         Added GetDropCnt and GetDropFile functions
  1040.                         Else not on next line problem?
  1041.  
  1042.                   1.4   Fixed yield problem
  1043. =========================================================================
  1044.